#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#include "data_structure.h"
#include "boosting_manager.h"

#include <vector>
using namespace std;

#define max_line_len 1024
int max_nr_attr = 64;

void predict(FILE *input, FILE *output, boosting_manager & bm, bool batch)
{
	int correct = 0;
	int total = 0;
	double error = 0;
	double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
	int tp = 0, fp = 0, fn = 0, tn = 0;
	
	boosting_node *x = (struct boosting_node *) malloc(max_nr_attr*sizeof(struct boosting_node));

	if(!batch) {
		fprintf(output, "label 1 0\n");
	}
	
	while(1)
	{
		int i = 0;
		int c;
		double target,v;

		if (fscanf(input,"%lf",&target)==EOF)
			break;

		while(1)
		{
			if(i>=max_nr_attr-1)	// need one more for index = -1
			{
				max_nr_attr *= 2;
				x = (struct boosting_node *) realloc(x,max_nr_attr*sizeof(struct boosting_node));
			}

			do {
				c = getc(input);
				if(c=='\n' || c==EOF) goto out2;
			} while(isspace(c));
			ungetc(c,input);
			if (fscanf(input,"%d:%lf",&x[i].index,&x[i].value) < 2)
			{
				fprintf(stderr,"Wrong input format at line %d\n", total+1);
				exit(1);
			}
			++i;
		}	

out2:
		x[i].index = -1;

		if(batch) {
			vector<double> results;
			bm.batch_test(x, results);
			v = results[results.size() - 1] >= 0.5 ? 1 : 0;
			for(unsigned l = 0; l < results.size(); l++) {
				if(l == results.size() - 1) {
					fprintf(output, "%g\n", results[l]);
				} else {
					fprintf(output, "%g\t", results[l]);
				}
			}
		} else {
			double value = bm.test(x);
			v = value >= 0.5 ? 1 : 0;
			int prediction = (int) v;
			fprintf(output,"%d %f %f\n",prediction, value, 1-value);
		}

		if(v == target)
			++correct;
		error += (v-target)*(v-target);
		sumv += v;
		sumy += target;
		sumvv += v*v;
		sumyy += target*target;
		sumvy += v*target;

		if(target == 1) {
			if(v == 1) {
				tp ++;
			} else {
				fn ++;
			}
		} else {
			if(v == 1) {
				fp ++;
			} else {
				tn ++;
			}
		}

		++total;
	}
	
	free(x);

	double recall = tp / (double)(tp + fn);
	double precision = tp / (double)(tp + fp);
	double f1 = 2 * recall * precision / (recall + precision);

	printf("Accuracy = %g%% (%d/%d) (classification)\n",
	       (double)correct/total*100,correct,total);

	printf("Recall = %g%% (%d/%d) (classification)\n",
	       recall*100,tp,(tp + fn));

	printf("Precision = %g%% (%d/%d) (classification)\n",
	       precision*100,tp,(tp + fp));

	printf("F1 = %g%% (classification)\n",
	       f1);

	printf("\n%d\t%d\n%d\t%d\n",
	       tp, fp, fn, tn);
}

int main_test(int argc, char ** argv) {
	if(argc != 5) {
		printf("usage: exe test test_file model_file result_file\n");
		return 0;
	}

	FILE *input, *output;
	input = fopen(argv[1],"r");

	if(input == NULL) {
		printf("cannot open %s\n", argv[1]);
	}

	char * model_file = argv[2];
	output = fopen(argv[3],"w");
	bool batch = atoi(argv[4]) == 1;

	boosting_manager bm;
	bm.load(model_file);
	predict(input,output, bm, batch);

	fclose(input);
	fclose(output);

	return 0;
}